<template>
	<!-- 展示盒子区域 -->
	<div id="container"></div>
</template>
  
<script>
// 引入three
import * as THREE from "three";
// 引入控制器
import {
	OrbitControls
} from 'three/addons/controls/OrbitControls.js';
// 引入控制面板
import GUI from 'lil-gui';
// 引入动画库
import * as TWEEN from '@tweenjs/tween.js';
// vue3中這連個不能用響應式的寫法會報錯
let scene = null; //场景
let mesh = null; // 网格模型
export default {
	data() {
		return {
			camera: null, // 相机
			renderer: null, //渲染器
			controls: null, //控制器
			// 控制面板 把数值放这里是为了好拿数据
			obj: {
				// 初始相机的位置
				x: 2,
				y: 3,
				z: 4,
			}
		};
	},
	mounted() {
		this.init();
		this.addModel()
		this.animate();
		this.initGui()
	},
	methods: {
		//1.初始化
		init: function () {
			// 1. 创建场景对象Scene
			scene = new THREE.Scene();

			// 加载立方体贴图 注意vue中的图片使用require加载 否则报错
			var textureLoader = new THREE.CubeTextureLoader();
			console.log(textureLoader);
			// 添加辅助观察的坐标系
			const axesHelper = new THREE.AxesHelper(150);
			scene.add(axesHelper);

			//环境光:没有特定方向，整体改变场景的光照明暗 不需要设置位置
			const ambient = new THREE.AmbientLight(0xffffff, 0.4);
			scene.add(ambient);

			/**
			 * 3.创建相机并设置
			 */
			// 获取盒子
			let container = document.getElementById("container");
			// 创建相机
			this.camera = new THREE.PerspectiveCamera(
				60,
				container.clientWidth / container.clientHeight,
				0.04,
				3000
			);
			this.camera.position.set(this.obj.x, this.obj.y, this.obj.z);
			this.camera.position.x = 1
			this.camera.lookAt(0, 0, 0);
			/**
			 * 4.创建渲染器对象
			 */
			this.renderer = new THREE.WebGLRenderer({
				antialias: true
			});
			// 设置渲染器的宽高为盒子的宽高
			this.renderer.setSize(container.clientWidth, container.clientHeight);
			// 添加渲染器到盒子中
			container.appendChild(this.renderer.domElement);

			//5.创建控件对象 没有这个就不能缩放拖拽
			this.controls = new OrbitControls(this.camera, this.renderer.domElement);

			// 开启模型拖拽缩放 //监听鼠标、键盘事件
			this.controls.addEventListener('change', () => {
				// 手动移动到需要的位置 打印出来当前的相机坐标 提供下面使用
				console.log(this.camera.position.x, this.camera.position.y, this.camera.position.z)
				// 如果OrbitControls改变了相机参数，重新调用渲染器渲染三维场景
				this.renderer.render(scene, this.camera); //执行渲染操作
			});

			this.animate()
		},

		// 加载模型
		addModel() {
			//网格模型添加到场景中
			let geometry = new THREE.BoxGeometry(4, 2, 2);
			let material = new THREE.MeshLambertMaterial({
				color: "white"
			});
			mesh = new THREE.Mesh(geometry, material);
			scene.add(mesh);
		},

		// 渲染函数
		animate() {
			// 切换相机位置必须要在这里执行这一步
			TWEEN.update();
			console.log(scene, this.camera,"====");
			this.renderer.render(scene, this.camera);
			requestAnimationFrame(this.animate);
		},


		//更新相机位置 参数来自于下面的gui方法调用时
		changeCameraPosition(cameraX, cameraY, cameraZ) {
			new TWEEN.Tween({
				x1: this.camera.position.x, // 初始相机x (获取的相机位置)
				y1: this.camera.position.y, // 初始相机y
				z1: this.camera.position.z, // 初始相机z
				x2: 0, // 初始控制点的中心点x
				y2: 0, // 初始控制点的中心点y
				z2: 0 // 初始控制点的中心点z
			}).to({
				x1: cameraX, // 切换后的相机x （来自参数）
				y1: cameraY, // 切换后的相机y
				z1: cameraZ, // 切换后的相机z
				x2: 2, // 切换后控制点的中心点x
				y2: 2, // 切换后控制点的中心点y
				z2: 2 // 切换后控制点的中心点z
			}, 1000)
				.easing(TWEEN.Easing.Cubic.InOut)
				// （这里不用动）
				.onUpdate((object) => {
					// 更新相机位置
					this.camera.position.set(object.x1, object.y1, object.z1)
					// 更新控制器位置
					this.controls.target.x = object.x2;
					this.controls.target.y = object.y2;
					this.controls.target.z = object.z2;
					this.controls.update();
				}).start();
		},

		// 添加控制面板
		initGui() {
			// 申明相机切换方法 下面用
			let obj = {
				// 车内
				internal: () => {
					// 点击之后要做什么（执行此方法切换相机位置）
					this.changeCameraPosition(0, 0.8, -1.4)
				},
				// 车外
				external: () => {
					// 点击之后要做什么（执行此方法切换相机位置）
					this.changeCameraPosition(3, 3, 4)
				}
			}
			// 初始化
			const gui = new GUI();
			// 添加一个按钮 点击执行对应的方法
			gui.add(obj, 'internal').name('内视角')
			gui.add(obj, 'external').name('外视角')
		},
	}
};
</script>
  
<style>
#container {
	width: 100%;
	height: 100%;
}
</style>